package com.zmn.oms.third.tc58.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.zmn.oms.third.base.dto.api.ApiInvokResult;
import com.zmn.oms.third.tc58.Tc58Consts;
import com.zmn.oms.third.tc58.dto.Tc58Response;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;

import java.util.*;

/**
 * 类描述：数据校验及加解密工具类
 *
 * @author LiangHailong
 * @date 2019/09/24 11:32
 */
@Slf4j
public final class Tc58Util {
    private static final String SIGN_TEST = "tc58test";
    private static final String LOG_HEAD = "58同城";

    /**
     * 解析请求数据
     * @param requestJson
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> ApiInvokResult<T> parseRequest(String requestJson, Class<T> tClass) {
        ApiInvokResult result = new ApiInvokResult();
        result.setSuccess(false);

        JSONObject jsonObject = JSON.parseObject(requestJson);
        // 存在订单数据
        if (jsonObject.get("data") != null) {
            String sign = jsonObject.getString("sign");

            Map<String, Object> map = jsonObject.getObject("data", new TypeReference<Map<String, Object>>(){});
            String localSign = sign(Tc58Consts.SECRET, map, null);
            if (SIGN_TEST.equals(sign) || Objects.equals(sign, localSign)) {
                T tc58Order = jsonObject.getObject("data", tClass);
                result.setData(tc58Order);

                result.setSuccess(true);
            }
            else {
                log.info("【{}-validate-sign】数据校验失败！ sign=[{}], LocalSign=[{}], ResponseBody=[{}]", LOG_HEAD,
                        sign, localSign, requestJson);
                result.setMsg(String.format("%s 数据校验失败", result.getMsg()));
            }
        }
        // 没有订单数据
        else {
            result.setMsg(String.format("%s 推送消息中不存在订单数据", result.getMsg()));
        }

        return result;
    }

    /**
     * 解析接口数据
     * @param responseJson
     * @param tClass
     * @param <T>
     * @return
     */
    public static <T> ApiInvokResult<T> parseResponse(String responseJson, Class<T> tClass) {
        ApiInvokResult result = new ApiInvokResult();

        Tc58Response<T> tc58Response = JSON.parseObject(responseJson, new TypeReference<Tc58Response<T>>(){});
        result.setSuccess(tc58Response.getCode() == 0); // 0代表成功，非0代表失败
        result.setMsg(tc58Response.getMessage());

        if (!result.isSuccess()) {
            return result;
        }

        if (tClass == null || tClass.getSimpleName().equals(Boolean.class.getSimpleName())) {
            return result;
        }

        JSONObject jsonObject = JSON.parseObject(responseJson);
        if (jsonObject.get("result") != null) {
            String sign = jsonObject.getString("sign");

            Map<String, Object> map = jsonObject.getObject("result", new TypeReference<Map<String, Object>>(){});
            String codeAndMsg = String.format("&code=%d&message=%s", tc58Response.getCode(), tc58Response.getMessage());
            String localSign = sign(Tc58Consts.SECRET, map, codeAndMsg);

            if (SIGN_TEST.equals(sign) || Objects.equals(sign, localSign)) {
                T resultData = jsonObject.getObject("result", tClass);
                result.setData(resultData);
            }
            else {
                log.info("【{}-validate-sign】数据校验失败！ sign=[{}], LocalSign=[{}], ResponseBody=[{}]", LOG_HEAD,
                        sign, localSign, responseJson);
                result.setMsg(String.format("%s 数据校验失败", result.getMsg()));
            }
        }

        return result;
    }

    /**
     * 获取sign
     * @param secretKey
     * @param params
     * @return
     */
    public static String sign(String secretKey, Map<String, Object> params, String codeAndMsg) {
        // keys排序
        List<String> keys = new ArrayList<>(params.size());
        params.forEach((key, value) -> {
            keys.add(key);
        });
        Collections.sort(keys);

        // 拼接params
        StringBuilder paramsBuilder = new StringBuilder();
        paramsBuilder.append("key=").append(secretKey);

        for (String key : keys) {
            Object value = params.get(key);
            if (value == null) {
                continue;
            }
            String valueStr = value.toString();
            if (StringUtils.isNotBlank(valueStr)) {
                paramsBuilder.append("&").append(key)
                        .append("=").append(valueStr);
            }
        }

        if (codeAndMsg != null) {
            paramsBuilder.append(codeAndMsg);
        }

        String paramsStr = paramsBuilder.toString();
        String sign = DigestUtils.md5Hex(paramsStr);
        log.debug("【{}-sign】sign=[{}], paramsStr=[{}]", sign, paramsStr);

        return sign;
    }

    /**
     * 获取sign
     * @param tc58Response
     * @return
     */
    public static String sign(Tc58Response<Boolean> tc58Response) {
        String params = String.format("key=%s&result=%b&code=%d&message=%s", Tc58Consts.SECRET,
                tc58Response.getResult(), tc58Response.getCode(), tc58Response.getMessage());

        String sign = DigestUtils.md5Hex(params);
        log.debug("【{}-sign】sign=[{}], paramsStr=[{}]", sign, params);

        return sign;
    }

}
